package com.lucky.common.util;

import ch.qos.logback.core.joran.spi.ActionException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class FileUtil {

    private static final Logger log = LoggerFactory.getLogger(FileUtil.class);
    /**
     * 上传地址
     */
    @Value("${lucky.file.tmp-path}")
    private static String fileTempPath;

    public static Path uploadFile(MultipartFile file, String dir, String filename) {
        try {
            byte[] bytes = file.getBytes();
            Path oPath = Paths.get(fileTempPath+file.getOriginalFilename());
            file.transferTo(oPath);
            Path nPath = Paths.get(dir + filename);
            Files.createDirectories(nPath);
            Files.move(oPath, nPath, StandardCopyOption.REPLACE_EXISTING);
            return nPath;
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        }
    }

    public void download(String path, String fileName, HttpServletResponse response) throws Exception {
        log.info("需要下载的文件名称：{}",fileName);
        File downLoadFile = new File(path, fileName);
        log.info("文件绝对路径：{}",downLoadFile.getAbsolutePath());
        ServletOutputStream os = response.getOutputStream();
        response.setHeader("content-disposition","attachment;fileName="+ URLEncoder.encode(fileName,"UTF-8"));
        IOUtils.copy(new FileInputStream(downLoadFile),os);
        IOUtils.closeQuietly(os);
    }

    public static Path moveFile(String oldPath, String newPath) throws Exception {
        return Files.move(Paths.get(oldPath), Paths.get(newPath));
    }

    public static boolean renameFile(File oldPath, File newPath) throws Exception {
        return oldPath.renameTo(newPath);
    }

    public static boolean create(String filePath, String fileName, String content, boolean append) {

            File path = new File(filePath);
            if (!path.exists()) {
                path.mkdirs();
            }
            File file = new File(filePath + fileName);
            if (!file.exists()) {
                try {
                    file.createNewFile();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
		try (Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file.getAbsoluteFile()), "UTF-8"))){
            writer.write(content);
            System.out.println("finish");
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 根据系统获取文件路径
     *
     * @param url
     * @return
     */
    public static String getRootPath(String url) {

        String os = System.getProperty("os.name");
        if (os != null && os.startsWith("Windows")) {
            url = "d:" + url;
        }

        return url;
    }



    /**
     * 判断是否为IE浏览器
     *
     * @param agent
     * @return
     */
    public static boolean isMSIEFun(String agent) {
		return (agent != null && (agent.indexOf("MSIE") != -1 || agent.indexOf("rv:11") != -1) || agent.indexOf("Edge") != -1);   //增加判断IE11问题	增加edge浏览器问题
    }

    /**
     * 单一文件下载
     *
     * @param request
     * @param response
     * @param dirPath
     * @param filename
     * @throws ActionException
     * @throws IOException
     * @throws IOException
     * @throws Exception
     */
    public static void downloadfile(HttpServletRequest request, HttpServletResponse response, String dirPath, String filename) throws Exception {
        if (StringUtils.isEmpty(dirPath)) {

        } else if (dirPath.contains("..") || filename.toUpperCase().contains("%2E%2E")) {
            throw new Exception("非法参数！");
        }

        File file = new File(dirPath);

        if (file.exists() && file.isFile()) {
            InputStream ins = null;
            BufferedInputStream bins = null;
            OutputStream outs = null;
            BufferedOutputStream bouts = null;

            String agent = request.getHeader("User-Agent");
            boolean isMSIE = isMSIEFun(agent);
            try {
                if (isMSIE) {
					/*
					filename = URLEncoder.encode(filename, "UTF-8");
					IE应用这种方式输出文件名，经与张超确认暂不解决
					*/
                    filename = new String(filename.getBytes("GBK"), "ISO-8859-1");
                } else {
                    filename = new String(filename.getBytes("UTF-8"), "ISO-8859-1");
                }
                response.setContentType("application/x-msdownload");// 设置response内容的类型
                response.setHeader("Content-disposition", "attachment;filename=" + filename);// 设置头部信息

                ins = new FileInputStream(dirPath);
                bins = new BufferedInputStream(ins);// 放到缓冲流里面
                outs = response.getOutputStream();// 获取文件输出IO流
                bouts = new BufferedOutputStream(outs);

                int bytesRead = 0;
                byte[] buffer = new byte[8192];

                while ((bytesRead = bins.read(buffer, 0, buffer.length)) != -1)// 开始向网络传输文件流
                {
                    bouts.write(buffer, 0, bytesRead);
                }

                if (bouts != null) bouts.flush();// 这里一定要调用flush()方法
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } finally {
                if (bouts != null) bouts.close();
                if (outs != null) outs.close();
                if (bins != null) bins.close();
                if (ins != null) ins.close();
            }
        } else {
            throw new Exception("文件不存在,下载失败！");
        }
    }

    public static void downLoadFiles(List<File> files, String zipFileName, HttpServletRequest request, HttpServletResponse response) throws Exception {
        try {
            /**创建一个临时压缩文件，
             * 我们会把文件流全部注入到这个文件中
             * 这里的文件你可以自定义是.rar还是.zip*/
            File dir = new File(FileUtil.getRootPath("/rfpfile/app/temp"));
            if (!dir.exists()) {
                dir.mkdirs();
            }
            File file = new File(FileUtil.getRootPath("/rfpfile/app/temp/temp.rar"));
            if (!file.exists()) {
                file.createNewFile();
            }
            response.reset();
            //response.getWriter()
            //创建文件输出流
            FileOutputStream fous = new FileOutputStream(file);
            /**打包的方法我们会用到ZipOutputStream这样一个输出流,
             * 所以这里我们把输出流转换一下*/
            ZipOutputStream zipOut = new ZipOutputStream(fous);
            /**这个方法接受的就是一个所要打包文件的集合，
             * 还有一个ZipOutputStream*/
            for (File file11 : files) {
                zipFile(file11, zipOut);
            }
            zipOut.close();
            fous.close();
            downloadZip(file, zipFileName, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public static void downLoadFiles(List<File> files, HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        try {
            /**创建一个临时压缩文件，
             * 我们会把文件流全部注入到这个文件中
             * 这里的文件你可以自定义是.rar还是.zip*/
            File file = new File(FileUtil.getRootPath(fileTempPath + "temp.rar"));
            if (!file.exists()) {
                file.createNewFile();
            }
            //创建文件输出流
            FileOutputStream fous = new FileOutputStream(file);
            /**打包的方法我们会用到ZipOutputStream这样一个输出流,
             * 所以这里我们把输出流转换一下*/
            ZipOutputStream zipOut = new ZipOutputStream(fous);
            /**这个方法接受的就是一个所要打包文件的集合，
             * 还有一个ZipOutputStream*/
            for (File file11 : files) {
                zipFile(file11, zipOut);
            }
            zipOut.close();
            fous.close();
            downloadZip(file, file.getName(), response);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static void downloadZip(File file, String fileName, HttpServletResponse response) {
        try {
            // 清空response
            response.reset();
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            response.setHeader("Content-Disposition", "attachment;filename=" + ((StringUtils.isNotBlank(fileName)) ? fileName : file.getName()));

			byte[] fb = FileUtils.readFileToByteArray(file);
			OutputStream os = response.getOutputStream();
			os.write(fb);
            os.flush();
            os.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            try {
                File f = new File(file.getPath());
                f.delete();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 根据输入的文件与输出流对文件进行打包
     */
    public static void zipFile(File inputFile, ZipOutputStream zos) throws IOException {
            if (inputFile.exists()) {
                /**如果是目录的话这里是不采取操作的，
                 * 至于目录的打包正在研究中*/
                if (inputFile.isFile()) {
					try(BufferedInputStream bins = new BufferedInputStream(new FileInputStream(inputFile), 512))
					{
						ZipEntry entry = new ZipEntry(inputFile.getName());
						zos.putNextEntry(entry);
						// 向压缩文件中输出数据
						int nNumber;
						byte[] buffer = new byte[512];
						while ((nNumber = bins.read(buffer)) != -1) {
							zos.write(buffer, 0, nNumber);
						}
					}
                } else {
                    try {
                        File[] files = inputFile.listFiles();
                        for (int i = 0; i < files.length; i++) {
                            zipFile(files[i], zos);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
    }

    public static void compressFiles(List<Map<String, String>> filePaths, String zipFilePath) throws IOException {
        // 确保输出目录存在
        File zipFile = new File(zipFilePath);
        File parentDir = zipFile.getParentFile();
        if (parentDir != null && !parentDir.exists()) {
            parentDir.mkdirs();
        }

        // 使用try-with-resources确保流关闭
        try (FileOutputStream fos = new FileOutputStream(zipFile);
             ZipOutputStream zos = new ZipOutputStream(fos)) {

            for (Map<String, String> fileInfo : filePaths) {
                String sourceFilePath = fileInfo.get("filePath");
                String zipEntryName = fileInfo.get("fileName");

                if (sourceFilePath == null || zipEntryName == null) {
                    throw new IllegalArgumentException("文件信息缺少filePath或fileName");
                }

                File sourceFile = new File(sourceFilePath);
                if (!sourceFile.exists() || !sourceFile.isFile()) {
                    throw new FileNotFoundException("文件不存在或不是普通文件: " + sourceFilePath);
                }

                addToZip(sourceFile, zipEntryName, zos);
            }
        }
    }

    private static void addToZip(File file, String entryName, ZipOutputStream zos) throws IOException {
        // 使用try-with-resources管理文件输入流
        try (FileInputStream fis = new FileInputStream(file)) {
            ZipEntry zipEntry = new ZipEntry(entryName);
            zos.putNextEntry(zipEntry);

            byte[] buffer = new byte[1024];
            int length;
            while ((length = fis.read(buffer)) > 0) {
                zos.write(buffer, 0, length);
            }
            zos.closeEntry();
        }
    }

    public static void createDirectory(String path) {
        File file = new File(path);
        if (!file.exists()) {
            boolean mkdirs = file.mkdirs();
        }
    }


	public static boolean delete(String fullPath) {
		try {
			File myDelFile = new File(fullPath);
			myDelFile.delete();
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}


	/**
	 * 大文件拷贝
	 * @param source
	 * @param target
	 * @param allocate
	 * @throws IOException
	 */
    public static void copy(String source, String target, int allocate) throws IOException {
        try (
                FileInputStream inputStream = new FileInputStream(source);
                FileChannel inChannel = inputStream.getChannel();

                FileOutputStream outputStream = new FileOutputStream(target);
                FileChannel outChannel = outputStream.getChannel()
        ) {
            ByteBuffer byteBuffer = ByteBuffer.allocate(allocate);
            int length = inChannel.read(byteBuffer);
            while (length != -1) {
                byteBuffer.flip();//读取模式转换写入模式
                outChannel.write(byteBuffer);
                byteBuffer.clear(); //清空缓存，等待下次写入
                // 再次读取文本内容
                length = inChannel.read(byteBuffer);
            }
        }
    }

	/**
	 *
	 * @param sfPath
	 * @param tfPath
	 * @throws IOException
	 */
    public static void copy(String sfPath, String tfPath) throws IOException {

        File sf = new File(sfPath);
        File tf = new File(tfPath);

        try (FileInputStream fi = new FileInputStream(sf);
             FileOutputStream fo = new FileOutputStream(tf);
             FileChannel in = fi.getChannel();
             FileChannel out = fo.getChannel()
        ) {
            in.transferTo(0, in.size(), out);//连接两个通道，并且从in通道读取，然后写入out通道
        }
    }


}
